package com.blandware.atleap.webapp.filter;

import com.blandware.atleap.common.Constants;
import com.blandware.atleap.model.core.User;
import com.blandware.atleap.model.core.UserCookie;
import com.blandware.atleap.service.core.UserManager;
import com.blandware.atleap.webapp.util.core.RequestUtil;
import com.blandware.atleap.webapp.util.core.SslUtil;
import com.blandware.atleap.webapp.util.core.WebappConstants;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.commons.validator.GenericValidator;
import org.springframework.context.ApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.util.Date;
import java.util.Map;

/**
 * <p>This class is used to filter all requests to the <code>Action</code>
 * servlet and detect if a user is authenticated.
 * </p>
 * <p><a href="ActionFilter.java.html"><i>View Source</i></a></p>
 *
 * @author Matt Raible <a href="mailto:matt@raibledesigns.com">&lt;matt@raibledesigns.com&gt;</a>
 * @version $Revision: 1.13 $ $Date: 2006/07/03 17:58:13 $
 * @web.filter name="actionFilter"
 * <p>Change this value to true if you want to secure your entire application.
 * This can also be done in web-security.xml by setting <transport-guarantee>
 * to CONFIDENTIAL.</p>
 * @web.filter-init-param name="isSecure" value="${secure.application}"
 */
public class ActionFilter implements Filter {
	protected Boolean secure = Boolean.FALSE;
	protected transient final Log log = LogFactory.getLog(ActionFilter.class);
	protected FilterConfig config = null;

    /**
     * Initializes the filter with a given filter config
     *
     * @param config The config to use
     * @throws ServletException
     */
	public void init(FilterConfig config) throws ServletException {
		this.config = config;

		/* This determines if the application uconn SSL or not */
		secure = Boolean.valueOf(config.getInitParameter("isSecure"));
	}

	/**
	 * Destroys the filter.
	 */
	public void destroy() {
		config = null;
	}

    /**
     * Filters a request
     *
     * @param req   Filtered request
     * @param resp  Response that will be result of filtering
     * @param chain Chain of following filters
     * @throws IOException
     * @throws ServletException
     */
	public void doFilter(ServletRequest req, ServletResponse resp,
	                     FilterChain chain)
	        throws IOException, ServletException {
		// cast to the types I want to use
		HttpServletRequest request = (HttpServletRequest) req;
		HttpServletResponse response = (HttpServletResponse) resp;
		HttpSession session = request.getSession(true);
        ServletContext context = config.getServletContext();

        Map appConfig = (Map) context.getAttribute(Constants.CONFIG);
        boolean secureLogin = ((Boolean) appConfig.get(Constants.SECURE_LOGIN)).booleanValue();
        boolean loggingIn = !GenericValidator.isBlankOrNull(request.getParameter(WebappConstants.LOGGING_IN));

		// do pre filter work here
		// If using https, switch to http
        String redirectString =
		        SslUtil.getRedirectString(request, context,
		                secure.booleanValue() || (secureLogin && loggingIn));

		if ( redirectString != null ) {
			if ( log.isDebugEnabled() ) {
				log.debug("protocol switch needed, redirecting to '" +
				        redirectString + "'");
			}

			// Redirect the page to the desired URL
			response.sendRedirect(response.encodeRedirectURL(redirectString));

			// ensure we don't chain to requested resource
			return;
		}

		String username = request.getRemoteUser();
		User user = (User) session.getAttribute(Constants.USER_KEY);

		// only for UserCounterListener in order to correctly count users after context reload
		if ( user != null ) {
			session.setAttribute(Constants.USER_KEY, user);
		}

		// user authenticated, empty user object
		if ( username != null && user == null ) {
			ApplicationContext ctx =
			        WebApplicationContextUtils.getRequiredWebApplicationContext(context);

			UserManager userManager = (UserManager) ctx.getBean(Constants.USER_MANAGER_BEAN);
			user = userManager.retrieveUser(username);
			session.setAttribute(Constants.USER_KEY, user);

			// if user wants to be remembered, create a remember me cookie
			if ( session.getAttribute(Constants.LOGIN_COOKIE) != null ) {
				session.removeAttribute(Constants.LOGIN_COOKIE);


				UserCookie userCookie = new UserCookie();
				userCookie.setDateCreated(new Date());
				String loginCookie = null;
				try {
					loginCookie = userManager.createUserCookie(userCookie, username);
				} catch ( Exception e ) {
					throw new ServletException(e);
				}
				RequestUtil.setCookie(response, Constants.LOGIN_COOKIE,
				        loginCookie, request.getContextPath());
			}
		}

		chain.doFilter(request, response);
	}
}
